﻿using System;
using System.Collections.Generic;
using System.Reflection;

namespace Smile.Mvvm.Mediator
{
    internal class MessageToActionsMap
    {
        // @Public
        public void AddAction(string message, object target, MethodInfo method, Type actionType)
        {
            if (message == null)
            {
                throw new ArgumentNullException("MessageToAction: message cannot be null.");
            }

            if (method == null)
            {
                throw new ArgumentNullException("MessageToAction: method cannot be null.");
            }

            lock (_map)
            {
                if (!_map.ContainsKey(message))
                {
                    _map.Add(message, new List<WeakAction>());
                }

                _map[message].Add(new WeakAction(target, method, actionType));
            }
        }

        public Stack<Delegate> GetActions(string message)
        {
            if (message == null)
            {
                throw new ArgumentNullException("MessageToAction: message cannot be null.");
            }

            Stack<Delegate> actions;
            lock (_map)
            {
                if (!_map.ContainsKey(message))
                {
                    return null;
                }

                List<WeakAction> weakActions = _map[message];
                actions = new Stack<Delegate>(weakActions.Count);
                for (int i = weakActions.Count - 1; i >= 0; --i)
                {
                    if (weakActions[i] == null)
                    {
                        continue;
                    }

                    Delegate action = weakActions[i].CreateAction();
                    if (action != null)
                    {
                        actions.Push(action);
                    }
                    else
                    {
                        weakActions.Remove(weakActions[i]);
                    }
                }


                if (weakActions.Count == 0)
                {
                    _map.Remove(message);
                }
            }
            return actions;
        }

        public bool TryGetParameterType(string message, out Type parameterType)
        {
            if (message == null)
            {
                throw new ArgumentNullException("MessageToAction: message cannot be null.");
            }

            parameterType = null;
            List<WeakAction> weakActions;
            lock (_map)
            {
                if (!_map.TryGetValue(message, out weakActions) || weakActions.Count == 0)
                {
                    return false;
                }
                parameterType = weakActions[0].ParameterType;
            }

            return true;
        }


        // @Private
        readonly Dictionary<string, List<WeakAction>> _map = new Dictionary<string, List<WeakAction>>();
    }
}
